<template>
  <div class="terminal-container" ref="terminalContainer">
    <div class="terminal-header">
      <div class="terminal-title">{{ sessionName || '新终端会话' }}</div>
      <div class="terminal-actions">
        <a-button type="text" size="small" @click="toggleFullscreen">
          <template #icon>
            <FullscreenOutlined v-if="!isFullscreen" />
            <FullscreenExitOutlined v-else />
          </template>
        </a-button>
        <a-button type="text" size="small" @click="openSettings">
          <template #icon><SettingOutlined /></template>
        </a-button>
        <a-button type="text" size="small" @click="reconnect">
          <template #icon><ReloadOutlined /></template>
        </a-button>
        <a-button type="text" size="small" danger @click="closeTerminal">
          <template #icon><CloseOutlined /></template>
        </a-button>
      </div>
    </div>
    <div class="terminal-body" ref="terminalElement"></div>
    
    <!-- 设置对话框 -->
    <a-modal
      v-model:visible="settingsVisible"
      title="终端设置"
      :footer="null"
      width="400px"
    >
      <div class="settings-form">
        <a-form layout="vertical">
          <a-form-item label="字体大小">
            <a-slider
              v-model:value="fontSize"
              :min="10"
              :max="24"
              :step="1"
              @change="applyFontSize"
            />
          </a-form-item>
          
          <a-form-item label="字体">
            <a-select v-model:value="fontFamily" @change="applyFontFamily">
              <a-select-option value="'Consolas', 'Microsoft YaHei Mono', monospace">Consolas + 微软雅黑</a-select-option>
              <a-select-option value="'Microsoft YaHei Mono', monospace">微软雅黑等宽</a-select-option>
              <a-select-option value="'Cascadia Code', 'Microsoft YaHei', monospace">Cascadia Code</a-select-option>
              <a-select-option value="'Courier New', 'SimSun', monospace">Courier New + 宋体</a-select-option>
              <a-select-option value="'Source Code Pro', 'NSimSun', monospace">Source Code Pro + 新宋体</a-select-option>
              <a-select-option value="'Monaco', 'KaiTi', monospace">Monaco + 楷体</a-select-option>
            </a-select>
          </a-form-item>
          
          <a-form-item label="主题">
            <a-select v-model:value="theme" @change="applyTheme">
              <a-select-option value="default">默认</a-select-option>
              <a-select-option value="dark">暗黑</a-select-option>
              <a-select-option value="light">明亮</a-select-option>
              <a-select-option value="solarized">Solarized</a-select-option>
            </a-select>
          </a-form-item>
          
          <a-form-item label="光标样式">
            <a-select v-model:value="cursorStyle" @change="applyCursorStyle">
              <a-select-option value="block">块状</a-select-option>
              <a-select-option value="underline">下划线</a-select-option>
              <a-select-option value="bar">竖线</a-select-option>
            </a-select>
          </a-form-item>
        </a-form>
      </div>
    </a-modal>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
import { Terminal } from 'xterm';
import { FitAddon } from '@xterm/addon-fit';
import { FullscreenOutlined, FullscreenExitOutlined, SettingOutlined, ReloadOutlined, CloseOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { getTerminalWSUrl } from '@/api';
import 'xterm/css/xterm.css';

// 检测平台
const platform = typeof navigator !== 'undefined' ? navigator.platform : '';

// 组件属性
const props = defineProps({
  sessionId: {
    type: String,
    default: null
  },
  initialSettings: {
    type: Object,
    default: () => ({})
  }
});

// 事件
const emit = defineEmits(['close', 'error', 'connected', 'disconnected', 'session-created']);

// 终端状态
const terminal = ref(null);
const fitAddon = ref(null);
const websocket = ref(null);
const terminalElement = ref(null);
const terminalContainer = ref(null);
const isConnected = ref(false);
const isFullscreen = ref(false);
const sessionName = ref('');
const currentSessionId = ref(props.sessionId);

// 终端设置
const settingsVisible = ref(false);
const fontSize = ref(16);
const fontFamily = ref("'Consolas', 'Microsoft YaHei Mono', monospace");
const theme = ref('default');
const cursorStyle = ref('block');

// 加载用户设置
const loadSettings = () => {
  try {
    const savedSettings = localStorage.getItem('terminal-settings');
    if (savedSettings) {
      const settings = JSON.parse(savedSettings);
      fontSize.value = settings.fontSize || 16;
      fontFamily.value = settings.fontFamily || "'Cascadia Code', monospace";
      theme.value = settings.theme || 'default';
      cursorStyle.value = settings.cursorStyle || 'block';
    }
  } catch (error) {
    console.error('加载终端设置失败:', error);
  }
};

// 保存用户设置
const saveSettings = () => {
  try {
    const settings = {
      fontSize: fontSize.value,
      fontFamily: fontFamily.value,
      theme: theme.value,
      cursorStyle: cursorStyle.value
    };
    localStorage.setItem('terminal-settings', JSON.stringify(settings));
  } catch (error) {
    console.error('保存终端设置失败:', error);
  }
};

// 初始化终端
const initTerminal = () => {
  try {
    // 加载用户设置
    loadSettings();
    
    // 应用初始设置
    if (props.initialSettings) {
      fontSize.value = props.initialSettings.fontSize || fontSize.value;
      fontFamily.value = props.initialSettings.fontFamily || fontFamily.value;
      theme.value = props.initialSettings.theme || theme.value;
      cursorStyle.value = props.initialSettings.cursorStyle || cursorStyle.value;
    }
    
    // 检查DOM元素是否存在
    if (!terminalElement.value) {
      console.error('终端DOM元素不存在，无法初始化终端');
      return;
    }
    
    // 创建终端实例
    terminal.value = new Terminal({
      fontSize: fontSize.value,
      fontFamily: fontFamily.value,
      cursorStyle: cursorStyle.value,
      cursorBlink: true,
      allowTransparency: true,
      scrollback: 10000,
      theme: getThemeColors(theme.value),
      convertEol: true,
      lineHeight: 1.2,
      rendererType: 'canvas',
      disableStdin: false,
      screenReaderMode: false,
      cols: 80,
      rows: 24,
      rightClickSelectsWord: true,
      allowProposedApi: true,
      windowsMode: typeof platform !== 'undefined' && platform === 'win32', // 启用Windows模式（如果在Windows上）
      fontWeightBold: 700
    });
    
    // 创建FitAddon用于自适应大小
    fitAddon.value = new FitAddon();
    terminal.value.loadAddon(fitAddon.value);
    
    // 打开终端
    terminal.value.open(terminalElement.value);
    
    // 适应容器大小
    nextTick(() => {
      if (fitAddon.value) {
        fitAddon.value.fit();
      }
    });
    
    // 处理终端输入
terminal.value.onData(data => {
  if (isConnected.value) {
    // 发送数据到后端
    sendTerminalInput(data);
    
    // 注意：我们不在这里添加本地回显，因为标准终端行为是
    // 由后端的shell程序负责回显。添加本地回显可能导致字符重复。
  }
});
    
    // 处理终端大小变化
    terminal.value.onResize(size => {
      if (isConnected.value) {
        sendTerminalResize(size.cols, size.rows);
      }
    });
    
    // 连接WebSocket
    connectWebSocket();
  } catch (error) {
    console.error('初始化终端失败:', error);
    emit('error', error);
  }
};

// 连接WebSocket
const connectWebSocket = async () => {
  try {
    // 获取WebSocket URL
    const wsUrl = await getTerminalWSUrl();
    console.log('正在连接终端WebSocket:', wsUrl);
    
    // 创建WebSocket连接
    websocket.value = new WebSocket(wsUrl);
    
    // 连接建立时
    websocket.value.onopen = () => {
      console.log('终端WebSocket连接已建立');
      
      // 发送初始化消息
      if (terminal.value) {
        const { cols, rows } = terminal.value;
        const initMessage = {
          type: 'init',
          cols,
          rows,
          sessionId: currentSessionId.value
        };
        console.log('发送初始化消息:', initMessage);
        websocket.value.send(JSON.stringify(initMessage));
      } else {
        console.error('终端实例不存在，无法发送初始化消息');
        // 使用默认值
        const initMessage = {
          type: 'init',
          cols: 80,
          rows: 24,
          sessionId: currentSessionId.value
        };
        websocket.value.send(JSON.stringify(initMessage));
      }
    };
    
    // 接收消息
    websocket.value.onmessage = (event) => {
      console.log('收到WebSocket消息:', event.data);
      handleWebSocketMessage(event.data);
    };
    
    // 连接关闭
    websocket.value.onclose = (event) => {
      console.log('终端WebSocket连接已关闭, 代码:', event.code, '原因:', event.reason);
      isConnected.value = false;
      emit('disconnected');
      
      // 显示重连提示
      if (terminal.value) {
        terminal.value.write('\r\n\x1b[31m连接已断开。点击重新连接按钮或按Enter键重新连接。\x1b[0m\r\n');
      }
      
      // 如果不是用户主动关闭，尝试自动重连
      if (event.code !== 1000 && event.code !== 1001) {
        setTimeout(() => {
          console.log('尝试自动重新连接...');
          reconnect();
        }, 3000);
      }
    };
    
    // 连接错误
    websocket.value.onerror = (error) => {
      console.error('终端WebSocket连接错误:', error);
      isConnected.value = false;
      emit('error', error);
      
      // 显示错误提示
      if (terminal.value) {
        terminal.value.write('\r\n\x1b[31m连接错误。请检查网络连接和后端服务是否正常运行。\x1b[0m\r\n');
      }
    };
    
    // 启动心跳检测
    startHeartbeat();
  } catch (error) {
    console.error('连接终端WebSocket失败:', error);
    if (terminal.value) {
      terminal.value.write(`\r\n\x1b[31m连接失败: ${error.message}\x1b[0m\r\n`);
      terminal.value.write('\r\n\x1b[31m请确保后端服务已启动，并且WebSocket端点可访问。\x1b[0m\r\n');
    }
    emit('error', error);
  }
};

// 处理WebSocket消息
const handleWebSocketMessage = (data) => {
  try {
    const message = JSON.parse(data);
    
    switch (message.type) {
      case 'init':
        // 初始化成功
        isConnected.value = true;
        currentSessionId.value = message.sessionId;
        emit('connected');
        emit('session-created', message.sessionId);
        
        // 显示欢迎消息
        if (terminal.value) {
          terminal.value.clear();
          terminal.value.write('连接成功！\r\n');
        }
        break;
        
      case 'output':
        // 接收终端输出
        if (message.data && terminal.value) {
          try {
            // 尝试解码Base64数据
            const binaryString = atob(message.data);
            const bytes = new Uint8Array(binaryString.length);
            for (let i = 0; i < binaryString.length; i++) {
              bytes[i] = binaryString.charCodeAt(i);
            }
            
            // 尝试使用TextDecoder解码为UTF-8
            try {
              const decoder = new TextDecoder('utf-8', { fatal: false });
              const decodedText = decoder.decode(bytes);
              terminal.value.write(decodedText);
            } catch (e) {
              console.error('UTF-8解码失败:', e);
              // 回退到直接使用二进制字符串
              terminal.value.write(binaryString);
            }
          } catch (e) {
            console.error('解码终端输出失败:', e);
            // 如果解码失败，尝试直接输出
            terminal.value.write(message.data);
          }
        }
        break;
        
      case 'heartbeat':
        // 心跳响应，无需处理
        break;
        
      case 'error':
        // 错误消息
        console.error('终端错误:', message.message);
        if (terminal.value) {
          terminal.value.write(`\r\n\x1b[31m错误: ${message.message}\x1b[0m\r\n`);
        }
        break;
        
      default:
        console.warn('未知消息类型:', message);
    }
  } catch (error) {
    console.error('处理WebSocket消息失败:', error);
  }
};

// 发送终端输入
const sendTerminalInput = (data) => {
  if (websocket.value && websocket.value.readyState === WebSocket.OPEN) {
    try {
      // 优化编码过程，减少转换步骤
      const encoder = new TextEncoder();
      const bytes = encoder.encode(data);
      
      // 直接将字节数组转换为Base64
      const binaryString = String.fromCharCode.apply(null, bytes);
      const encodedData = btoa(binaryString);
      
      // 立即发送数据
      websocket.value.send(JSON.stringify({
        type: 'input',
        data: encodedData
      }));
    } catch (e) {
      console.error('编码终端输入失败:', e);
      // 如果编码失败，尝试备用方法
      try {
        const encodedData = btoa(unescape(encodeURIComponent(data)));
        websocket.value.send(JSON.stringify({
          type: 'input',
          data: encodedData
        }));
      } catch (e2) {
        console.error('备用编码方法也失败:', e2);
        // 最后的尝试
        try {
          websocket.value.send(JSON.stringify({
            type: 'input',
            data: btoa(data)
          }));
        } catch (e3) {
          console.error('所有编码方法都失败:', e3);
        }
      }
    }
  }
};

// 发送终端大小调整
const sendTerminalResize = (cols, rows) => {
  if (websocket.value && websocket.value.readyState === WebSocket.OPEN) {
    websocket.value.send(JSON.stringify({
      type: 'resize',
      cols,
      rows
    }));
  }
};

// 心跳检测
let heartbeatInterval = null;
const startHeartbeat = () => {
  // 清除可能存在的旧心跳
  if (heartbeatInterval) {
    clearInterval(heartbeatInterval);
  }
  
  // 每30秒发送一次心跳
  heartbeatInterval = setInterval(() => {
    if (websocket.value && websocket.value.readyState === WebSocket.OPEN) {
      websocket.value.send(JSON.stringify({
        type: 'heartbeat'
      }));
    }
  }, 30000);
};

// 重新连接
const reconnect = () => {
  // 关闭现有连接
  closeWebSocket();
  
  // 清空终端（添加null检查）
  if (terminal.value) {
    terminal.value.clear();
    terminal.value.write('正在重新连接...\r\n');
  }
  
  // 重新连接
  connectWebSocket();
};

// 关闭WebSocket连接
const closeWebSocket = () => {
  if (heartbeatInterval) {
    clearInterval(heartbeatInterval);
    heartbeatInterval = null;
  }
  
  if (websocket.value) {
    websocket.value.onclose = null; // 防止触发onclose事件
    websocket.value.close();
    websocket.value = null;
  }
  
  isConnected.value = false;
};

// 关闭终端
const closeTerminal = () => {
  closeWebSocket();
  emit('close', currentSessionId.value);
};

// 切换全屏
const toggleFullscreen = () => {
  isFullscreen.value = !isFullscreen.value;
  
  if (isFullscreen.value) {
    terminalContainer.value.classList.add('fullscreen');
  } else {
    terminalContainer.value.classList.remove('fullscreen');
  }
  
  // 调整终端大小
  nextTick(() => {
    fitAddon.value.fit();
  });
};

// 打开设置
const openSettings = () => {
  settingsVisible.value = true;
};

// 应用字体大小
const applyFontSize = (size) => {
  terminal.value.options.fontSize = size;
  fitAddon.value.fit();
  saveSettings();
};

// 应用字体
const applyFontFamily = (font) => {
  terminal.value.options.fontFamily = font;
  fitAddon.value.fit();
  saveSettings();
};

// 应用主题
const applyTheme = (themeName) => {
  terminal.value.options.theme = getThemeColors(themeName);
  saveSettings();
};

// 应用光标样式
const applyCursorStyle = (style) => {
  terminal.value.options.cursorStyle = style;
  saveSettings();
};

// 获取主题颜色
const getThemeColors = (themeName) => {
  const themes = {
    default: {
      foreground: '#ffffff',
      background: '#000000',
      cursor: '#ffffff',
      selection: 'rgba(255, 255, 255, 0.3)',
      black: '#000000',
      red: '#e06c75',
      green: '#98c379',
      yellow: '#d19a66',
      blue: '#61afef',
      magenta: '#c678dd',
      cyan: '#56b6c2',
      white: '#ffffff',
    },
    dark: {
      foreground: '#f8f8f2',
      background: '#282a36',
      cursor: '#f8f8f2',
      selection: 'rgba(248, 248, 242, 0.3)',
      black: '#000000',
      red: '#ff5555',
      green: '#50fa7b',
      yellow: '#f1fa8c',
      blue: '#bd93f9',
      magenta: '#ff79c6',
      cyan: '#8be9fd',
      white: '#f8f8f2',
    },
    light: {
      foreground: '#2e3436',
      background: '#f6f5f4',
      cursor: '#2e3436',
      selection: 'rgba(46, 52, 54, 0.3)',
      black: '#2e3436',
      red: '#cc0000',
      green: '#4e9a06',
      yellow: '#c4a000',
      blue: '#3465a4',
      magenta: '#75507b',
      cyan: '#06989a',
      white: '#d3d7cf',
    },
    solarized: {
      foreground: '#839496',
      background: '#002b36',
      cursor: '#839496',
      selection: 'rgba(131, 148, 150, 0.3)',
      black: '#073642',
      red: '#dc322f',
      green: '#859900',
      yellow: '#b58900',
      blue: '#268bd2',
      magenta: '#d33682',
      cyan: '#2aa198',
      white: '#eee8d5',
    }
  };
  
  return themes[themeName] || themes.default;
};

// 窗口大小调整处理
const handleResize = () => {
  try {
    if (fitAddon.value && terminal.value) {
      fitAddon.value.fit();
    }
  } catch (error) {
    console.error('终端大小调整失败:', error);
  }
};

// 生命周期钩子
onMounted(() => {
  // 初始化终端
  nextTick(() => {
    try {
      initTerminal();
    } catch (error) {
      console.error('终端初始化失败:', error);
      emit('error', { message: '终端初始化失败', error });
    }
  });
  
  // 监听窗口大小变化
  window.addEventListener('resize', handleResize);
});

onUnmounted(() => {
  // 关闭WebSocket连接
  closeWebSocket();
  
  // 销毁终端
  if (terminal.value) {
    terminal.value.dispose();
  }
  
  // 移除事件监听
  window.removeEventListener('resize', handleResize);
});

// 监听sessionId变化
watch(() => props.sessionId, (newSessionId) => {
  if (newSessionId !== currentSessionId.value) {
    currentSessionId.value = newSessionId;
    
    // 如果已连接，则重新连接
    if (isConnected.value) {
      reconnect();
    }
  }
});

// 导出方法
defineExpose({
  reconnect,
  closeTerminal,
  terminal: terminal
});
</script>

<style scoped>
.terminal-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid #e8e8e8;
  border-radius: 4px;
  overflow: hidden;
  background-color: #000;
  transition: all 0.3s;
}

.terminal-container.fullscreen {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 9999;
  border: none;
  border-radius: 0;
}

.terminal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 10px;
  height: 40px;
  background-color: #f0f0f0;
  border-bottom: 1px solid #e8e8e8;
}

.terminal-title {
  font-weight: bold;
  font-size: 14px;
  color: #333;
}

.terminal-actions {
  display: flex;
  gap: 5px;
}

.terminal-body {
  flex: 1;
  padding: 5px;
  overflow: hidden;
}

.settings-form {
  padding: 10px;
}

:deep(.xterm) {
  padding: 5px;
  height: 100%;
}

:deep(.xterm-viewport) {
  overflow-y: auto;
}
</style> 